package com.github.xiaolyuh.base;

import com.github.xiaolyuh.configcenter.ConfigCenter;
import com.github.xiaolyuh.constant.CacheConstant;
import com.github.xiaolyuh.entity.RedisName;
import com.github.xiaolyuh.enums.CacheCodeEnum;
import com.github.xiaolyuh.exception.CacheException;
import com.github.xiaolyuh.redis.clinet.RedisProperties;
import com.github.xiaolyuh.redis.clinet.SingleRedisClient;
import com.github.xiaolyuh.utils.FastJSONHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class RedisBasicCacheManager extends SingleRedisClient implements BasicCacheManager {

    private static final Logger logger = LoggerFactory.getLogger(RedisBasicCacheManager.class);

    // 批量查询超时时间:200毫秒
    private static final Long BATCH_GET_WARN_TIME = 200L;

    private static final Long SIMPLE_GET_WARN_TIME = 100L;

    private RedisName redisName;

    public RedisBasicCacheManager(RedisProperties properties) {
        super(properties);
    }

    @Override
    public boolean set(String key, Object value, int expireTime) throws CacheException {
        try {
            if (!isCacheEnable()) {
                return true;
            }
            long startTime = System.currentTimeMillis();
            byte[] bytes = serialize(value);
            this.set(key, bytes, expireTime);
            if (logger.isDebugEnabled()) {
                logger.debug("[cache]redis cache set key={} value={}", key, FastJSONHelper.serialize(value));
            }
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;
            if (costTime > SIMPLE_GET_WARN_TIME) {
                logger.info(String.format("[cache]redis cache set cost time : %s ms,key:%s", costTime, key));
            }
            return Boolean.TRUE;
        } catch (Exception e) {
            logger.error("[cache]redis cache set key error", e);
            throw new CacheException(CacheCodeEnum.FAIL.getCode(), e.getMessage());
        } catch (Throwable e) {
            logger.error("[cache]redis cache set key error", e);
            throw new CacheException(CacheCodeEnum.FAIL);
        }
    }

    @Override
    public Object get(String key, Class clazz)  {
        try {
            if (!isCacheEnable()) {
                return null;
            }
            long startTime = System.currentTimeMillis();
            Object value = this.get(key, clazz);
            if (logger.isDebugEnabled()) {
                if (value != null) {
                    logger.debug("[cache]redis cache get key={} value={}", key, value);
                }
            }
            long endTime = System.currentTimeMillis();
            long costTime = endTime - startTime;
            if (costTime > SIMPLE_GET_WARN_TIME) {
                logger.info(String.format("[cache]redis cache get cost time : %s ms,key:%s", costTime, key));
            }
            return value;
        } catch (Exception e) {
            logger.error("[cache]redis cache get key error", e);
        } catch (Throwable e) {
            logger.error("[cache]redis cache get key error", e);
        }
        return null;
    }

    @Override
    public boolean isCacheEnable() {
        return ConfigCenter.allowRedisCache();
    }

    @Override
    public boolean delete(String key) throws CacheException {
        try {
            if (!isCacheEnable()) {
                return true;
            }
            this.delete(key);
            if (logger.isDebugEnabled()) {
                logger.debug("[cache]redis cache delete key={}", key);
            }
            return Boolean.TRUE;
        } catch (Exception e) {
            logger.error("[cache]redis cache delete key error", e);
            throw new CacheException(CacheCodeEnum.FAIL.getCode(), e.getMessage());
        } catch (Throwable e) {
            logger.error("[cache]redis cache delete key error", e);
            throw new CacheException(CacheCodeEnum.FAIL);
        }
    }

    private byte[] serialize(Object value) throws IOException {
        byte[] bytes;
        if(Objects.equals(value, CacheConstant.NIL_STRING)){
            bytes = CacheConstant.NIL_BYTES;
        }else{
            bytes = FastJSONHelper.serializeBytes(value);
        }
        return bytes;
    }

    private Object deserialize(byte[] bytes, Class clazz) throws java.io.IOException {
        Object value = null;
        if (bytes != null) {
            if (Arrays.equals(CacheConstant.NIL_BYTES, bytes)) {
                value = CacheConstant.NIL_STRING;
            } else {
                value = FastJSONHelper.deSerializeObject(bytes, clazz);
            }
        }
        return value;
    }

    //*************************参数校验*************************

    private boolean checkArgs(List<String> keyList) {
        return keyList == null || keyList.isEmpty() || !isCacheEnable();
    }

}
